package unittests;

import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;

import org.joda.time.DateTime;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import clientserver.DummyServer;
import clientserver.DummyUIRootModel;

import vcp.client.exceptions.EmptyRequestException;
import vcp.client.request.CustomerCheckInRequest;
import vcp.client.request.CustomerCheckoutRequest;
import vcp.client.request.CustomerRegularCheckInRequest;
import vcp.client.request.Request;
import vcp.client.utility.Common.UserNotification;
import vcp.entity.Car;
import vcp.entity.Subscription;
import vcp.enums.SiteEnum;
import vcp.server.factories.DAOFactoryAbstract;
import vcp.server.factories.MySQLDAOFactory;
import vcp.server.utility.timedecision.TimeDecisionMinute;

public class CalculateParkingChargeUnitTest
{
	private static DummyServer server;
	private static DummyUIRootModel client;

	private DAOFactoryAbstract daoFactory;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
		server = new DummyServer(5555, new TimeDecisionMinute());
		server.listen();

		Thread.sleep(1000);

		client = new DummyUIRootModel();
		client.connectToServer(InetAddress.getLocalHost().getHostAddress(), 5555);

		Thread.sleep(1000);
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception
	{
		CalculateParkingChargeUnitTest.client.closeConnection();
		CalculateParkingChargeUnitTest.server.stopListening();
		CalculateParkingChargeUnitTest.server.close();

		client = null;
		server = null;
	}

	@Before
	public void setUp() throws Exception
	{
		this.daoFactory = new MySQLDAOFactory();
	}

	@After
	public void tearDown() throws Exception
	{
		this.daoFactory = null;
	}

	@Test
	public void invalidCarID()
	{
		int carID = 1;

		this.sendToServer(new CustomerCheckoutRequest(carID, SiteEnum.SITE_1));

		CalculateParkingChargeUnitTest.client.waitForResponse();
		Assert.assertNull(CalculateParkingChargeUnitTest.client.getResponse().getData());
	}

	@SuppressWarnings("unchecked")
	@Test
	public void carIDNotInCorrectSite()
	{
		int carID = 6789;
		int customerID = 12345;

		this.sendToServer(new CustomerCheckInRequest(customerID, carID, SiteEnum.SITE_1));
		CalculateParkingChargeUnitTest.client.waitForResponse();

		ArrayList<Serializable> serializableList = (ArrayList<Serializable>) CalculateParkingChargeUnitTest.client.getResponse().getData();
		Subscription subscription = (Subscription) serializableList.get(0);
		this.sendToServer(new CustomerRegularCheckInRequest(subscription, "slavariv@gmail.com", new DateTime()));
		CalculateParkingChargeUnitTest.client.waitForResponse();

		this.sendToServer(new CustomerCheckoutRequest(carID, SiteEnum.SITE_2));
		CalculateParkingChargeUnitTest.client.waitForResponse();
		Assert.assertNull(CalculateParkingChargeUnitTest.client.getResponse().getData());

		Car car = this.daoFactory.getCarDAO().findByID(carID);
		int subscriptionID = car.getSubscriptionID();
		this.daoFactory.getCarDAO().deleteByID(carID);
		this.daoFactory.getSubscriptionDAO().deleteByID(subscriptionID);
		this.daoFactory.getCustomerDAO().deleteByID(customerID);
		this.daoFactory.getUserDAO().deleteByID(customerID);
	}

	@Test
	public void calculatingCasualSubscriperParkingCharge()
	{
		int carID = 3245640;
		int customerID = 312345682;

		this.sendToServer(new CustomerCheckInRequest(customerID, carID, SiteEnum.SITE_2));
		CalculateParkingChargeUnitTest.client.waitForResponse();

		this.sendToServer(new CustomerCheckoutRequest(carID, SiteEnum.SITE_2));
		CalculateParkingChargeUnitTest.client.waitForResponse();
		Assert.assertEquals(UserNotification.SUBSCRIBEL_PARKING_DONE, CalculateParkingChargeUnitTest.client.getResponse().getData());

		this.daoFactory.getCarDAO().updateArrivalTime(carID, new DateTime(2001, 1, 1, 0, 0, 0));
		this.daoFactory.getCarDAO().updateLastCheckOutDate(carID, new DateTime(2001, 1, 1, 0, 0, 0));
	}

	@Test
	public void calculatingFullSubscriberParkingChargeWhenExceeds14Days()
	{
		int carID = 3245642;
		int customerID = 312345684;

		this.sendToServer(new CustomerCheckInRequest(customerID, carID, SiteEnum.SITE_2));
		CalculateParkingChargeUnitTest.client.waitForResponse();

		this.daoFactory.getCarDAO().updateArrivalTime(carID, new DateTime(2014, 2, 2, 0, 0, 0));

		this.sendToServer(new CustomerCheckoutRequest(carID, SiteEnum.SITE_2));
		CalculateParkingChargeUnitTest.client.waitForResponse();
		Assert.assertNull(CalculateParkingChargeUnitTest.client.getResponse().getData());

		this.daoFactory.getCarDAO().updateArrivalTime(carID, new DateTime(2001, 1, 1, 0, 0, 0));
		this.daoFactory.getCarDAO().updateLastCheckOutDate(carID, new DateTime(2001, 1, 1, 0, 0, 0));
	}

	@Test
	public void calculatingFullSubscriberParkingChargeWhenNotExceeds14Days()
	{
		int carID = 3245642;
		int customerID = 312345684;

		this.sendToServer(new CustomerCheckInRequest(customerID, carID, SiteEnum.SITE_2));
		CalculateParkingChargeUnitTest.client.waitForResponse();

		this.daoFactory.getCarDAO().updateArrivalTime(carID, new DateTime(2014, 1, 2, 0, 0, 0));

		this.sendToServer(new CustomerCheckoutRequest(carID, SiteEnum.SITE_2));
		CalculateParkingChargeUnitTest.client.waitForResponse();
		Assert.assertNull(CalculateParkingChargeUnitTest.client.getResponse().getData());

		this.daoFactory.getCarDAO().updateArrivalTime(carID, new DateTime(2001, 1, 1, 0, 0, 0));
		this.daoFactory.getCarDAO().updateLastCheckOutDate(carID, new DateTime(2001, 1, 1, 0, 0, 0));
	}

	private void sendToServer(Request request)
	{
		try
		{
			CalculateParkingChargeUnitTest.client.registerAndSendRequest(request, null);
		}
		catch (EmptyRequestException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}
